/**
 * 路径动画绘制
 * 自动计算控制点，平滑的曲线
 */

 var storage = require("../../utils/storage");
 var dataProvider = require("./dataProvider");
 var zoomProvider = require("./zoomProvider");
 var consts = require("../../consts/consts");
 var paper, transform, points = [],
     controls = [],
     focusedPoint;
 var _RAD2DEG = 180 / Math.PI,
     _r1 = [],
     _r2 = [],
     _r3 = [],
     _corProps = {},
     Segment = function(a, b, c, d) {
         this.a = a;
         this.b = b;
         this.c = c;
         this.d = d;
         this.da = d - a;
         this.ca = c - a;
         this.ba = b - a;
     },
     _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,";
 var pathProvider = {
        changed: false,
        firstPointChanged: false,
        widgetId: null,
        widgetElClone: null,
        firstCurve: null,
        focusWidget: null,
        secondPoint:　null,
        paper: paper,
        transform: transform,
        points: points,
        dimensions: {},
        opt: {
            color: '#00FF19',
            strokeWidth: 2,
            strokeLinecap: "round",
            focusStrokeColor: '#fff',
            focusStrokeWidth: 2,
            discattr: {
                fill: "#fff",
                stroke: "#00FF19",
                r: 5,
                'stroke-width': 2
            },
            focusAttr: {
                fill: "#00FF19",
                stroke: "#000000",
                r: 5,
                'stroke-width': 2
            }
        },
        setPaper: function(paper) {  // 设置svg
            this.paper = paper;
        },
        setWidgetId: function(id) {  //设置元件
            this.widgetId = id;
        },
        setWidget: function(widget){
            this.focusWidget = widget;
        },
        setTimeline: function(timeline){
           this.focusTimeline = timeline ? timeline : this.focusTimline || {};  
        },
        setState: function(setState){
            this.setPathState = setState;
        },
        updateTimeline: function(updateTimeline){
            this.updatePathTimeline = updateTimeline;
        },
        updateWidget: function(updateWidget){
            this.updatePathWidget = updateWidget;
        },
        setTransform: function(transform) {  //同步pathCanvas和editorCanvas的中心，原有pathCanvas的算法中心点有偏差。见centerOffsetToBorderOffset， borderOffsetToCenterOffset
            this.transform = transform;
        },
        addPoint: function(x, y) {  //添加点
            this.points.push({
                x: x,
                y: y
            });
            this.updatePoints();
        },
        // 删除选中的点
        deletePoint: function() {
            var index = this.points.indexOf(this.focusedPoint);
            if (index == -1) return;
            this.points.splice(index, 1);
            this.updatePoints();
        },
        getPoints: function() {
            var points = [];
            for (var i = 0; i < this.points.length; i++) {
                var wp = this.offsetWidget(this.points[i]);
                points.push(wp);
//                if (i == 0){//去掉虚拟点
//                    var wp = this.offsetWidget(this.secondPoint);
//                    points.push(wp);
//                }
            };
            return points;
        },
        getFocusWidget:function () {
            return this.focusWidget;
        },
        clearPoints: function() {
            this.points = [];
            this.paper.clear();
            this.widgetElClone && this.widgetElClone.remove();
            delete this.widgetElClone;
        },
        offsetWidget:function(point){
            var fx = this.focusWidget.offset_x;
            var fy = this.focusWidget.offset_y;
            return {
                x:point.x + fx,
                y:point.y + fy
            };
        },
        offsetEditor:function(point,flag){
            var $editorPanel = $('.creator-edtor');
            var editorX = $editorPanel.scrollLeft();
            var editorY = $editorPanel.scrollTop();
            var offset = {
                x:editorX - 1300,
                y:editorY - 1300
            } ;
            return {
                x:point.x+(flag?offset.x:-offset.x),
                y:point.y-offset.y
            };
        },
        offsetPoints: function(points){
            var _points = [];
            var len = points.length;
            for(var i=0;i<len;i++){
                var wp = this.offsetWidget(points[i])  // 路径的相对坐标(路径点以第一个点(元件中心点)做参照系)转换到中心点坐标
                var op = this.centerOffsetToBorderOffset(wp.x, wp.y);  // 中心点坐标转换到边界坐标(样式使用的left，top)
                _points.push(op);
            }
            return _points;
        },
        // 每次只用把最后两个点连接起来就可以了
        updatePoints: function() {
            this.changed = true;
            if (this.points.length < 2)
                return

            var points = this.offsetPoints(this.points);
            this.paper.clear();
            this.controls = [];
            var pointObj = this.bezierThrough(points);

            var xPoints = pointObj.x,
                yPoints = pointObj.y;

            for (var i = 0; i < points.length - 1; i++) {
                this.createBezier(xPoints[i], yPoints[i], i);
                if (this.points[i].focus) {
                    this.focus(points[i].control);
                }
            };

            // 在第1,2个点中间绘制虚拟点

//            this.createVirtualPoint();//去掉虚拟点

            // 将元件的最终状态拷贝过来
            this.showWidgetInPathEnd();
        },
        broadcastEv: function () {
            var timeline = this.focusTimeline, an_types = timeline.an_types || [];
            for (var i = 0; i < an_types.length; i++) {
                var an_type = an_types[i];
                if ($.inArray(an_type.an_type, consts.WIDGET_HAS_PATH_ANIMATION_TYPE) != -1) {
                    if (pathProvider.changed){
                        an_type.points = pathProvider.getPoints();
                        pathProvider.changed = false;
                    }
                }
            };
            console.log(timeline)
            this.updatePathTimeline(timeline);
            this.setPathState({selectedTimeline: timeline});
            if(this.firstPointChanged){
                 this.setPathState({selectedWidget:this.focusWidget});
                 this.updatePathWidget(this.focusWidget);
            }
        },
        broadPosition: function () {
            var offset_x = this.focusWidget.offset_x,
                offset_y = this.focusWidget.offset_y;
            this.updatePathWidget(this.focusWidget);
        },
        createVirtualPoint: function() {
            var ptl = this.firstCurve.getTotalLength(),
                pv = this.firstCurve.getPointAtLength(ptl / 2),
                that = this,
                p;
//            getSecondPoint();//去掉虚拟点
            p = this.paper.circle(pv.x, pv.y, this.opt.radius).attr(this.opt.discattr);
            p.update = function(x, y) {
                var X = this.attr("cx") + x,
                    Y = this.attr("cy") + y;
                this.attr({
                    cx: X,
                    cy: Y
                });

                that.controls[0][1].update(x, y);
            }

            function move(dx, dy) {
                if (this.disableEvent) return false;
                var scale = parseFloat(zoomProvider.scale());
                this.update(dx/scale - (this.dx/scale || 0), dy/scale - (this.dy/scale || 0));
                this.dx = dx;
                this.dy = dy;
                return false;
            };
            function getSecondPoint(){
                var cx = that.controls[0][0].attr("cx");
                var cy = that.controls[0][0].attr("cy");
                var pvx = pv.x -cx;
                var pvy = cy-pv.y;
                var npv =new Object();
                npv["x"] = pvx;
                npv["y"] = pvy;
                that.secondPoint = npv;
                return npv;
            }
            function start() {
                this.dx = this.dy = 0;
                var p0 = that.points.shift();
//                var npv = getSecondPoint();//去掉虚拟点
//                that.points.unshift(npv);
                that.points.unshift(p0);
//                that.updatePoints();//去掉虚拟点
            };
            function end() {
//                that.broadcastEv();//去掉虚拟点
                return false;
            };
            p.drag(move, start, end);
        },
        showWidgetInPathEnd: function() {
            var oWidgetEl = $("#wgt-id-" + this.widgetId);
            if (!oWidgetEl.length) return;
            if (!this.widgetElClone) {
                this.widgetElClone = oWidgetEl.clone().attr({
                    id: "wgt-id-clone"
                }).addClass("clone").removeClass("focus");

                oWidgetEl.after(this.widgetElClone);
            };
            // 计算位置
            var points = this.offsetPoints(this.points);
            var lPoint = points[points.length - 1];
            var centerOffset = this.borderOffsetToCenterOffset(lPoint.x, lPoint.y);
            //var centerOffset = this.offsetEditor(centerOffset,true);  // AR3.0把pathCanvas大小调整到和editorCanvas一样大，故不需要再作此偏移
            var dimensions = {
                width: oWidgetEl.width(),
                height: oWidgetEl.height()
            };
            var borderOffset = this.centerOffsetToBorderOffsetByEditorCanvas(centerOffset.x, centerOffset.y, dimensions);

            this.widgetElClone.css({
                top: borderOffset.top,
                left: borderOffset.left
            });
        },
        createBezier: function(xps, yps, index) {
            var that = this,
                path, curve, control;
//            path = [
//                ["M", xps.a, yps.a],
//                ["C", xps.b, yps.b, xps.c, yps.c, xps.d, yps.d]
//            ];//贝塞尔曲线
            path = [
                ["M",xps.a,yps.a],
                ["L",xps.d,yps.d]
            ];//直线
            curve = this.paper.path(path).attr({
                stroke: this.opt.color,
                "stroke-width": this.opt.strokeWidth,
                "stroke-linecap": this.opt.strokeLinecap
            });
            control = this.paper.set(
                this.paper.circle(xps.a, yps.a, this.opt.radius).attr(this.opt.discattr),
                this.paper.circle(xps.d, yps.d, this.opt.radius).attr(this.opt.discattr)
            );

            var contextmenuClass = "path-context-menu";
            $('.editor-path-canvas svg').find('circle').contextmenu({
                target: '.' + contextmenuClass,
                onItem: that.handleOnContextMenu,
                deletePoint: that.deletePoint
            });
            if (index == 0) {
                control[0].disableEvent = true;
                this.firstCurve = curve;
            };
            control[0].update = function(x, y) {  // 拖动时重绘
                var X = this.attr("cx") + x,
                    Y = this.attr("cy") + y;
                this.attr({
                    cx: X,
                    cy: Y
                });
                // upate this.points
                that.points[index].x = X-that.controls[0][0].attr("cx");
                that.points[index].y = that.controls[0][0].attr("cy")-Y;
                that.updatePoints();
            };
            // 绑定point
            control[0].point = this.points[index];
            this.points[index].control = control[0];
            control[1].update = function(x, y) {
                var X = this.attr("cx") + x,
                    Y = this.attr("cy") + y;
                this.attr({
                    cx: X,
                    cy: Y
                });
                // upate this.points
                that.points[index + 1].x = X-that.controls[0][0].attr("cx");
                that.points[index + 1].y = that.controls[0][0].attr("cy")-Y;
                that.updatePoints();
            };
            // 绑定point
            control[1].point = this.points[index + 1];
            this.points[index + 1].control = control[1];
            function move(dx, dy) {
                if (this.disableEvent) {  // 拖动第一个点，需要修改widget的位置及points的坐标值，因为在pathCanvas内部points的参照系是第一个点
                    this.focusWidget = that.getFocusWidget();
                    this.focusWidget.offset_x += (dx - this.dx || 0);
                    this.focusWidget.offset_y -= (dy - this.dy || 0);
                    for (var ix = 1; ix < that.points.length; ix++) {
                        var item = that.points[ix];
                        item.x -= (dx - this.dx || 0);
                        item.y += (dy - this.dy || 0);
                    }
                    // 通过事件触发第一个点的位置时时修改
                    that.broadPosition();
                    that.updatePoints();
                    that.firstPointChanged = true;
                } else {
                    var scale = parseFloat(zoomProvider.scale());
                    this.update(dx / scale - (this.dx / scale || 0), dy / scale - (this.dy / scale || 0));
                    that.firstPointChanged = false;
                }
                this.dx = dx;
                this.dy = dy;
                return false;
            };
            function start() {
                this.dx = this.dy = 0;
            };
            function end() {
                that.broadcastEv();
                return false;
            };
            control.drag(move, start, end);
            control.click(function(e) {
                if (this.disableEvent) return false;
                that.focus(this);
            });
            control.mousedown(function(e){
                if (e.button==2){
                    if (this.disableEvent) return false;
                    that.focus(this);
                    document.oncontextmenu = function(e){return false;};//禁用鼠标右键菜单
                }
            })
            control.toFront();
            this.controls.push(control);
        },
        handleOnContextMenu: function (el, e){
            e.preventDefault();
            var data = storage.data;
            var menuItem = $(e.target || e.srcElement);
            var action = menuItem.attr("data-action");
            $('.editor-path-canvas svg').find('circle').data('context').closemenu();

            if (action){
                switch (action){
                    case "delete":
                        pathProvider.deletePoint();
                        break;
                    case "cancel":
                        break;
                }
            }
            return false;
        },
        focus: function(o) {
            for (var i = 0; i < this.controls.length; i++) {
                this.blur(this.controls[i]);
            };
            for (var i = 0; i < this.points.length; i++) {
                this.points[i].focus = false;
            };
            o.attr(this.opt.focusAttr);
            if (o.point) {
                o.point.focus = true
                this.focusedPoint = o.point;
            };
        },
        blur: function(o) {
            o.attr(this.opt.discattr);
            o.point && (o.point.focus = false);
        },
        // 中心点坐标转换为pathCanvas 所在左上角坐标
        centerOffsetToBorderOffset: function(xo, yo) {
            return {
                x: this.transform.offset_x + xo,  // AR3.0修改
                y: this.transform.offset_y - yo
            };
        },
        borderOffsetToCenterOffset: function(xp, yp) {
            return {
                x: xp - this.transform.offset_x,  // AR3.0修改
                y: this.transform.offset_y - yp
            };
        },
        centerOffsetToBorderOffsetByEditorCanvas: function(xo, yo, dimensions) {
            var borderOffset;
            borderOffset = {
                left: Math.round(this.transform.offset_x + xo - dimensions.width / 2),
                top: Math.round(this.transform.offset_y - yo - dimensions.height / 2)
            };
            return borderOffset;
        },
        bezierThrough: function(values, curviness, quadratic, basic, correlate, prepend) {
            var obj = {},
                props = [],
                first = prepend || values[0],
                i, p, a, j, r, l, seamless, last;
            correlate = (typeof(correlate) === "string") ? "," + correlate + "," : _correlate;
            if (curviness == null) {
                curviness = 1;
            }
            for (p in values[0]) {
                props.push(p);
            }
            //check to see if the last and first values are identical (well, within 0.05). If so, make seamless by appending the second element to the very end of the values array and the 2nd-to-last element to the very beginning (we'll remove those segments later)
            if (values.length > 1) {
                last = values[values.length - 1];
                seamless = true;
                i = props.length;
                while (--i > -1) {
                    p = props[i];
                    if (Math.abs(first[p] - last[p]) > 0.05) { //build in a tolerance of +/-0.05 to accommodate rounding errors. For example, if you set an object's position to 4.945, Flash will make it 4.9
                        seamless = false;
                        break;
                    }
                }
                if (seamless) {
                    values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens
                    if (prepend) {
                        values.unshift(prepend);
                    }
                    values.push(values[1]);
                    prepend = values[values.length - 3];
                }
            }
            _r1.length = _r2.length = _r3.length = 0;
            i = props.length;
            while (--i > -1) {
                p = props[i];
                _corProps[p] = (correlate.indexOf("," + p + ",") !== -1);
                obj[p] = this._parseAnchors(values, p, _corProps[p], prepend);
            }
            i = _r1.length;
            while (--i > -1) {
                _r1[i] = Math.sqrt(_r1[i]);
                _r2[i] = Math.sqrt(_r2[i]);
            }
            if (!basic) {
                i = props.length;
                while (--i > -1) {
                    if (_corProps[p]) {
                        a = obj[props[i]];
                        l = a.length - 1;
                        for (j = 0; j < l; j++) {
                            r = a[j + 1].da / _r2[j] + a[j].da / _r1[j];
                            _r3[j] = (_r3[j] || 0) + r * r;
                        }
                    }
                }
                i = _r3.length;
                while (--i > -1) {
                    _r3[i] = Math.sqrt(_r3[i]);
                }
            }
            i = props.length;
            j = quadratic ? 4 : 1;
            while (--i > -1) {
                p = props[i];
                a = obj[p];
                this._calculateControlPoints(a, curviness, quadratic, basic, _corProps[p]); //this method requires that _parseAnchors() and _setSegmentRatios() ran first so that _r1, _r2, and _r3 values are populated for all properties
                if (seamless) {
                    a.splice(0, j);
                    a.splice(a.length - j, j);
                }
            }
            return obj;
        },
        _parseAnchors: function(values, p, correlate, prepend) {
            var a = [],
                l, i, p1, p2, p3, tmp;
            if (prepend) {
                values = [prepend].concat(values);
                i = values.length;
                while (--i > -1) {
                    if (typeof((tmp = values[i][p])) === "string"){
                        if (tmp.charAt(1) === "=") {
                            values[i][p] = prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)); //accommodate relative values. Do it inline instead of breaking it out into a function for speed reasons
                        }
                    }
                }
            }
            l = values.length - 2;
            if (l < 0) {
                a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]);
                return a;
            }
            for (i = 0; i < l; i++) {
                p1 = values[i][p];
                p2 = values[i + 1][p];
                a[i] = new Segment(p1, 0, 0, p2);
                if (correlate) {
                    p3 = values[i + 2][p];
                    _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1);
                    _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2);
                }
            }
            a[i] = new Segment(values[i][p], 0, 0, values[i + 1][p]);
            return a;
        },
        _calculateControlPoints: function(a, curviness, quad, basic, correlate) {
            var l = a.length - 1,
                ii = 0,
                cp1 = a[0].a,
                i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl;
            for (i = 0; i < l; i++) {
                seg = a[ii];
                p1 = seg.a;
                p2 = seg.d;
                p3 = a[ii + 1].d;

                m1 = p2 - (p2 - p1) * curviness * 0.5;
                m2 = p2 + (p3 - p2) * curviness * 0.5;
                mm = p2 - (m1 + m2) / 2;

                m1 += mm;
                m2 += mm;

                seg.c = cp2 = m1;
                if (i !== 0) {
                    seg.b = cp1;
                } else {
                    seg.b = cp1 = seg.a + (seg.c - seg.a) * 0.6; //instead of placing b on a exactly, we move it inline with c so that if the user specifies an ease like Back.easeIn or Elastic.easeIn which goes BEYOND the beginning, it will do so smoothly.
                }

                seg.da = p2 - p1;
                seg.ca = cp2 - p1;
                seg.ba = cp1 - p1;

                ii++;
                cp1 = m2;
            }
            seg = a[ii];
            seg.b = cp1;
            seg.c = cp1 + (seg.d - cp1) * 0.4; //instead of placing c on d exactly, we move it inline with b so that if the user specifies an ease like Back.easeOut or Elastic.easeOut which goes BEYOND the end, it will do so smoothly.
            seg.da = seg.d - seg.a;
            seg.ca = seg.c - seg.a;
            seg.ba = cp1 - seg.a;
        }
    };
    module.exports = pathProvider;
